#include <OgreRoot.h>

#include <OgreOctreeNode.h>
#include <OgreOctreeSceneManager.h>

namespace Ogre
{
	unsigned long green = 0xFFFFFFFF;
	unsigned short OctreeNode::mIndexes[24] = {0, 1, 1, 2, 2, 3, 3, 0,
	0, 6, 6, 5, 5, 1,
	3, 7, 7, 4, 4, 2,
	6, 7, 5, 4};
	unsigned long OctreeNode::mColors[8] = {green, green, green, green, green, green, green, green};

	OctreeNode::OctreeNode(SceneManager* creator) : SceneNode(creator)
	{
		mOctant = 0;
	}

	OctreeNode::OctreeNode(SceneManager* creator, const String& name) : SceneNode(creator, name)
	{
		mOctant = 0;
	}

	OctreeNode::~OctreeNode()
	{}

	void OctreeNode::_removeNodeAndChildren()
	{
		static_cast<OctreeSceneManager*>(mCreator)->_removeOctreeNode(this);
		ChildNodeMap::iterator it = mChildren.begin();
		while (it != mChildren.end())
		{
			static_cast<OctreeNode*>(it->second)->_removeNodeAndChildren();
			++it;
		}
	}
	Node* OctreeNode::removeChild(unsigned short index)
	{
		OctreeNode* on = static_cast<OctreeNode*>(SceneNode::removeChild(index));
		on->_removeNodeAndChildren();
		return on;
	}
	Node* OctreeNode::removeChild(Node* child)
	{
		OctreeNode* on = static_cast<OctreeNode*>(SceneNode::removeChild(child));
		on->_removeNodeAndChildren();
		return on;
	}
	void OctreeNode::removeAllChildren()
	{
		ChildNodeMap::iterator i, iend;
		iend = mChildren.end();
		for (i = mChildren.begin(); i != iend; ++i)
		{
			OctreeNode* on = static_cast<OctreeNode*>(i->second);
			on->setParent(0);
			on->_removeNodeAndChildren();
		}
		mChildren.clear();
		mChildrenToUpdate.clear();
	}

	Node* OctreeNode::removeChild(const String& name)
	{
		OctreeNode* on = static_cast<OctreeNode*>(SceneNode::removeChild(name));
		on->_removeNodeAndChildren();
		return on;
	}

	void OctreeNode::_updateBounds(void)
	{
		mWorldAABB.setNull();
		mLocalAABB.setNull();

		ObjectMap::iterator i = mObjectsByName.begin();
		AxisAlignedBox bx;

		while (i != mObjectsByName.end())
		{
			bx = i->second->getBoundingBox();
			mLocalAABB.merge(bx);
			mWorldAABB.merge(i->second->getWorldBoundingBox(true));
			++i;
		}

		if (!mWorldAABB.isNull())
		{
			static_cast<OctreeSceneManager*>(mCreator)->_updateOctreeNode(this);
		}
	}

	bool OctreeNode::_isIn(AxisAlignedBox& box)
	{
		if (!mIsInSceneGraph || box.isNull()) return false;

		if (box.isInfinite())
			return true;

		Vector3 center = mWorldAABB.getMaximum().midPoint(mWorldAABB.getMinimum());

		Vector3 bmin = box.getMinimum();
		Vector3 bmax = box.getMaximum();

		bool centre = (bmax > center && bmin < center);
		if (!centre)
			return false;

		Vector3 octreeSize = bmax - bmin;
		Vector3 nodeSize = mWorldAABB.getMaximum() - mWorldAABB.getMinimum();
		return nodeSize < octreeSize;
	}

	void OctreeNode::_addToRenderQueue(Camera* cam, RenderQueue* queue,
		bool onlyShadowCasters, VisibleObjectsBoundsInfo* visibleBounds)
	{
		ObjectMap::iterator mit = mObjectsByName.Begin();

		while (mit != mObjectsByName.end())
		{
			MovableObject* mo = mit->second;
			queue->processVisibleObject(mo, cam, onlyShadowCasters, visibleBounds);

			++mit;
		}
	}

	void OctreeNode::getRenderOperation(RenderOperation& rend)
	{
	}
}
